﻿/******************************************************************************
 * GImageSearch.cs
 * 
 * This module implements the GImageSearch base search class and related types.
 *  
 * Date:   12/2008
 * 
 * Copyright (c) 2009, 2010, Mark Betz 
 * 
 * All rights reserved. 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 * 
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 *   * Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution. 
 *   * Neither the name of the Author nor the names of contributors may be 
 *     used to endorse or promote products derived from this software
 *     without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY MARK BETZ ''AS IS'' AND ANY  EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL MARK BETZ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * 
 */
using System;

namespace GSearch
{
    /// <summary>
    /// Type of the event arguments to GImageSearch events
    /// </summary>
    public class ImageSearchEventArgs : SearchEventArgs
    {
        /// <summary>
        /// Constructor used to initialize from a SearchEventArgs object.
        /// </summary>
        /// <param name="se"></param>
        public ImageSearchEventArgs( SearchEventArgs se )
        : base(se.Status, se.Result, se.Ex)
        {
        }

        /// <summary>
        /// Returns a reference to a <see cref="GSearch.GImageResponse"/> object
        /// that contains the response, for certain event types
        /// </summary>
        public new GImageResponse Result 
        { get { return (GImageResponse)(base.Result); } }
    }
    
    /// <summary>
    /// Enumerates the image search size filtering options.
    /// </summary>
    public enum SearchImageSize
    {
        /// <summary>
        /// Selects all images regardless of size
        /// </summary>
        All,
        
        /// <summary>
        /// Selects icon-sized images
        /// </summary>
        Icon,
        
        /// <summary>
        /// Selects small images
        /// </summary>
        Small,
        
        /// <summary>
        /// Selects medium images
        /// </summary>
        Medium,
        
        /// <summary>
        /// Selects large images
        /// </summary>
        Large,
        
        /// <summary>
        /// Selects extra large images
        /// </summary>
        XLarge,
        
        /// <summary>
        /// Selects XX sized images
        /// </summary>
        XXLarge,
        
        /// <summary>
        /// Selects huge images
        /// </summary>
        Huge
    };
    
    /// <summary>
    /// Enumerates the colorization filtering options.
    /// </summary>
    public enum SearchImageColorization
    {
        /// <summary>
        /// Selects all images regardless of colorization
        /// </summary>
        All,
        
        /// <summary>
        /// Selects grayscale images only
        /// </summary>
        Grayscale,
        
        /// <summary>
        /// Selects full color images only
        /// </summary>
        Color
    };
    
    /// <summary>
    /// Enumerates the available image type filters.
    /// </summary>
    public enum SearchImageType
    {
        /// <summary>
        /// Selects all images regardless of topical category
        /// </summary>
        All,
        
        /// <summary>
        /// selects images containing faces
        /// </summary>
        Face,
        
        /// <summary>
        /// Selects images from news stories
        /// </summary>
        News,
        
        /// <summary>
        /// Selects images that are photos
        /// </summary>
        Photo,
        
        /// <summary>
        /// Selects clip-art images
        /// </summary>
        Clipart
    };
    
    /// <summary>
    /// Enumerates the available image file type filters.
    /// </summary>
    public enum SearchImageFileType
    {
        /// <summary>
        /// Selects all images regardless of file format
        /// </summary>
        All,
        
        /// <summary>
        /// Selects only JPG images
        /// </summary>
        Jpg,
        
        /// <summary>
        /// Selects only PNG images
        /// </summary>
        Png,
        
        /// <summary>
        /// Selects only GIF images
        /// </summary>
        Gif,
        
        /// <summary>
        /// Selects only BMP images
        /// </summary>
        Bmp
    };

    /// <summary>
    /// [Experimental] Enumerates the available image color filters
    /// </summary>
    public enum SearchImageColor
    {
        /// <summary>
        /// Does not filter images for color tone
        /// </summary>
        All,
        
        /// <summary>
        /// Selects images with black tones
        /// </summary>
        Black,
        
        /// <summary>
        /// Selects images with bliue tones
        /// </summary>
        Blue,
        
        /// <summary>
        /// Selects images with brown tones
        /// </summary>
        Brown,

        /// <summary>
        /// Selects images with gray tones
        /// </summary>
        Gray,

        /// <summary>
        /// Selects images with green tones
        /// </summary>
        Green,

        /// <summary>
        /// Selects images with orange tones
        /// </summary>
        Orange,

        /// <summary>
        /// Selects images with pink tones
        /// </summary>
        Pink,

        /// <summary>
        /// Selects images with purple tones
        /// </summary>
        Purple,

        /// <summary>
        /// Selects images with red tones
        /// </summary>
        Red,

        /// <summary>
        /// Selects images with teal tones
        /// </summary>
        Teal,

        /// <summary>
        /// Selects images with white tones
        /// </summary>
        White,

        /// <summary>
        /// Selects images with yellow tones
        /// </summary>
        Yellow
    }

    /// <summary>
    /// ImageSearchArgs derives from <see cref="GSearch.SearchArgs"/> and implements
    /// image search-specific arguments.
    /// <example>
    /// The following code illustrates how to create and use the ImageSearchArgs class:
    /// <code>
    /// GImageSearch gis = new GImageSearch();
    /// ImageSearchArgs isa = new ImageSearchArgs();
    /// isa.Terms = "Jennifer Connelly";
    /// GImageResponse resp = gis.Search(isa);
    /// </code>
    /// </example>
    /// </summary>
    public class ImageSearchArgs : SearchArgs
    {
        /// <summary>
        /// Default constructor for the ImageSearchArgs class.
        /// </summary>
        public ImageSearchArgs()
        {
            Filter = SearchSafety.Full;
            ImageSize = SearchImageSize.All;
            Colorization = SearchImageColorization.All;
            Color = SearchImageColor.All;
            ImageType = SearchImageType.All;
            FileType = SearchImageFileType.All;
            SearchDomain = "";
        }
        
        /// <summary>
        /// ToQueryString overrides the base class version. It calls the
        /// base class version to get the root of the query string, and then
        /// builds the rest of the parameters.
        /// </summary>
        /// <returns>A System.String containing the complete set of querystring
        /// arguments for the specified search.</returns>
        public override string ToQueryString()
        {
            string qry = base.ToQueryString();
            
            // safe= level of offensive image screening
            qry += "&safe=" + ArgStrings.safeFilter[Convert.ToInt32(Filter)];
            
            // imgsz= return images in the specified size category
            if ( SearchImageSize.All != ImageSize )
                qry += "&imgsz=" + ArgStrings.imageSize[Convert.ToInt32(ImageSize)];
            
            // imgc= return images with the specified coloration
            if ( SearchImageColorization.All != Colorization )
                qry += "&imgc=" + ArgStrings.colorization[Convert.ToInt32(Colorization)];
            
            // imgcolor = return images with the specified color tones
            if ( SearchImageColor.All != Color )
                qry += "&imgcolor=" + ArgStrings.colors[Convert.ToInt32(Color)];
            
            // imgtype= return images in the specified topical categories
            if ( SearchImageType.All != ImageType )
                qry += "&imgtype=" + ArgStrings.imageType[Convert.ToInt32(ImageType)];
            
            // as_filetype= return images of the specified image format
            if ( SearchImageFileType.All != FileType )
                qry += "&as_filetype=" + ArgStrings.fileType[Convert.ToInt32(FileType)];
            
            // as_sitesearch= search within the specified domain only
            if ( "" != SearchDomain )
                qry += "&as_sitesearch=" + Uri.EscapeUriString(SearchDomain);
                
            return qry;
        }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchSafety"/> enum giving the
        /// level of filtering that should be peformed to remove offensive images.
        /// </summary>
        public SearchSafety Filter { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchImageSize"/> enum giving the
        /// general image size desired from the search.
        /// </summary>
        public SearchImageSize ImageSize { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchImageColorization"/> enum giving the
        /// colorization characteristics desired from the search.
        /// </summary>
        public SearchImageColorization Colorization { get; set; }

        /// <summary>
        /// A value from the <see cref="GSearch.SearchImageColor"/> enum giving the
        /// colorization characteristics desired from the search.
        /// <remarks>Added in version 1.2.0.0</remarks>
        /// </summary>
        public SearchImageColor Color { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchImageType"/> enum giving the
        /// topical category of image desired from the search.
        /// </summary>
        public SearchImageType ImageType { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchImageFileType"/> enum
        /// giving the type of image file format desired from the search.
        /// </summary>
        public SearchImageFileType FileType { get; set; }
        
        /// <summary>
        /// A System.String containing the complete URL address of the Internet
        /// domain which should be searched for images.
        /// </summary>
        public string SearchDomain { get; set; }
    }

    /// <summary>
    /// The GImageSearch class provides an interface for searching images using Google.
    /// It derives from <see cref="GSearch.GSearchCore"/> which does a large part of
    /// the work.
    /// <example>
    /// The following example shows how to use the GImageSearch class to search the web
    /// for images using Google:
    /// <code>
    /// GImageSearch gis = new GImageSearch();
    /// ImageSearchArgs isa = new ImageSearchArgs();
    /// isa.Terms = "Jennifer Connelly";
    /// GImageResponse resp = gis.Search(isa);
    /// if ( resp.Response.Results.Length > 0 )
    ///     // process results
    /// </code>
    /// </example>
    /// </summary>
    public class GImageSearch : GSearchCore
    {
#if (!SILVERLIGHT)
        /// <summary>
        /// Performs a syncronous search for images using the supplied arguments. The
        /// calling thread blocks until results are returned or an exception is thrown.
        /// This method is not available in the Silverlight version of the libraries.
        /// </summary>
        /// <param name="args"><see cref="GSearch.ImageSearchArgs"/> containing the search arguments</param>
        /// <returns><see cref="GSearch.GImageResponse"/> containing the results</returns>
        /// <exception cref="Exception">if an error occurs during the search</exception>
        public GImageResponse Search(ImageSearchArgs args)
        {
            return (GImageResponse)base.Search(args); 
        }
#endif

        /// <summary>
        /// Peforms an asyncronous search for images using the supplied arguments. The
        /// calling thread returns immediately, and results or errors are indicated by
        /// raising the SearchFailed, SearchComplete, or SearchProgressChanged events.
        /// Results are returned on the UI thread.
        /// </summary>
        /// <param name="args"><see cref="GSearch.ImageSearchArgs"/> containing the search arguments</param>
        /// <exception cref="Exception">if an error occurs during the search</exception>
        public void SearchAsync(ImageSearchArgs args)
        {
            base.SearchAsync( args );
        }

        /// <summary>
        /// This event is raised when the search is complete and the results
        /// are ready to be returned to the client.
        /// </summary>
        public event EventHandler<ImageSearchEventArgs> SearchComplete;
        
        /// <summary>
        /// This event is raised when the search fails for some reason. The event
        /// arguments Ex property will reference the exception.
        /// </summary>
        public event EventHandler<ImageSearchEventArgs> SearchFailed;
        
        /// <summary>
        /// This event is raised when key steps in the search process are
        /// completed. See the SearchStatus enumeration for possible values
        /// for the ImageSearchEventArgs.Status parameter.
        /// <seealso cref="GSearch.SearchStatus"/>
        /// </summary>
        public event EventHandler<ImageSearchEventArgs> SearchProgressChanged;

        /// <summary>
        /// Returns a System.String containing a complete uri for the video search
        /// service
        /// </summary>
        public override string ServiceURI
        {
            get { return base.ServiceURI + ImageResources.ServiceURI; }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchComplete event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchComplete(SearchEventArgs e)
        {
            EventHandler<ImageSearchEventArgs> ev = SearchComplete;
            if (null != ev)
            {
                ImageSearchEventArgs ie = new ImageSearchEventArgs(e);
                ev( this, ie );
            }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchFailed event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchFailed(SearchEventArgs e)
        {
            EventHandler<ImageSearchEventArgs> ev = SearchFailed;
            if (null != ev)
            {
                ImageSearchEventArgs ie = new ImageSearchEventArgs(e);
                ev(this, ie);
            }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchProgressChanged event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchProgressChanged(SearchEventArgs e)
        {
            EventHandler<ImageSearchEventArgs> ev = SearchProgressChanged;
            if (null != ev)
            {
                ImageSearchEventArgs ie = new ImageSearchEventArgs(e);
                ev(this, ie);
            }
        }

        /// <summary>
        /// Deserialize is called from the base when the search returns a valid
        /// result stream, it refers the call to the base class DeserializeImpl
        /// which actually does the work of deserialization.
        /// </summary>
        /// <param name="result">Stream result passed from the base class</param>
        /// <returns>Instance of <see cref="GSearch.GImageResponse"/> as GResponse</returns>
        protected override GResponse Deserialize(System.IO.Stream result)
        {
            return DeserializeImpl<GImageResponse>(result);
        }
    }
}
